<script setup>
import { CanvasRenderer } from 'echarts/renderers'
import { use } from 'echarts/core'
import { LineChart, BarChart } from 'echarts/charts'
import { create, all } from 'mathjs'
import katex from 'katex'
import 'katex/dist/katex.min.css'

import _ from 'lodash'
import {
  VisualMapComponent,
  TitleComponent,
  TooltipComponent,
  LegendComponent,
  GridComponent,
  MarkLineComponent,
  MarkPointComponent,
  ToolboxComponent

} from 'echarts/components'
import VChart, { THEME_KEY } from 'vue-echarts'
use([
  VisualMapComponent,
  TitleComponent,
  TooltipComponent,
  ToolboxComponent,
  LegendComponent,
  CanvasRenderer,
  LineChart,
  BarChart,
  GridComponent,
  MarkLineComponent,
  MarkPointComponent
])

const { proxy } = getCurrentInstance()
const dialogVisible = ref(false)
const option = ref({})
const dlgTitle = ref('')
const polynomialExpressions = ref([])
const polynomialsData = ref([])
const times = ref(2)
const initChats = (title, legend, xData, seriesData, xName) => {
  option.value = {
    toolbox: {
      show: true,
      left: 'right',
      feature: {
        saveAsImage: { show: true },
        restore: { show: true },
        dataView: { show: true }
      }
    },
    /* title: {
      text: title
    }, */
    tooltip: {
      trigger: 'axis'
    },
    legend: {
      data: legend
    },
    xAxis: {
      type: 'category',
      data: xData,
      name: xName,
      axisLabel: {
        show: true
      }
    },
    yAxis: {
      type: 'value',
      axisLine: { show: true }
    },
    series: seriesData
  }
}

const show = (data, form, dictMap) => {
  dialogVisible.value = true
  if (form.drawType === 'manual') {
    const orderData = _.orderBy(data, [(item) => Number(item[form.xAxis])], ['asc'])
    const allYValues = data.map(item => item[form.yAxis])
    console.log(form)
    const minY = Math.min(...allYValues)
    const maxY = Math.max(...allYValues)
    const padding = (maxY - minY) * 0.1
    const xData = []
    const seriesData = []
    const legend = []
    let title = `${dictMap.get(form.xAxis)}下,`
    orderData.forEach(item => {
      xData.push(item[form.xAxis])
    })
    form.yAxis.forEach((item, index) => {
      title = title.concat(`${dictMap.get(item)},`)
      seriesData.push({
        name: dictMap.get(item),
        type: form.chartType,
        stack: 'Total',
        data: [],
        smooth: true,
        markPoint: {
          data: [
            { type: 'max', name: 'Max' },
            { type: 'min', name: 'Min' }
          ]
        },
        markLine: {
          data: [{ type: 'average', name: 'Avg' }]
        }
      })
      legend.push(dictMap.get(item))
      orderData.forEach(dataItem => {
        seriesData[index].data.push(Number(dataItem[item]))
      })
    })
    title = title.slice(0, -1)
    dlgTitle.value = title
    initChats(title, legend, xData, seriesData, dictMap.get(form.xAxis))
    handleData(xData, orderData, form, dictMap)
  } else {
    dlgTitle.value = `${dictMap.get(form.xAxis)}下${dictMap.get(form.groupYAxis)}`
    handleGroupData(data, form, dictMap)
    initGroupCharts(form, data, dictMap)
  }
}
const initGroupCharts = (form, data, dictMap) => {
  console.log(form)
  /* const data = [
    { mach: 0.120, angle: 0.8, slip: 1.000 },
    { mach: 0.120, angle: 0.0, slip: 0.998 },
    { mach: 0.120, angle: 1.2, slip: 0.996 },
    // 省略其他数据
    { mach: 0.260, angle: 0.0, slip: 1.000 },
    { mach: 0.260, angle: 0.4, slip: 0.999 }
    // 省略其他数据
  ] */
  const allYValues = data.map(item => item[form.groupYAxis])
  let minY = Math.min(...allYValues)
  let maxY = Math.max(...allYValues)
  const padding = (maxY - minY) * 0.1
  minY -= padding
  maxY += padding
  const groupedData = data.reduce((result, currentValue) => {
    // 获取分组的key值
    (result[currentValue[form.groupKey]] = result[currentValue[form.groupKey]] || []).push(currentValue)
    return result
  }, {})
  const series = Object.keys(groupedData).map(key => {
    return {
      name: `${dictMap.get(form.groupKey)} ${key}`,
      type: form.chartType,
      smooth: true,
      barWidth: '5',
      data: groupedData[key].map(item => [item[form.xAxis], item[form.groupYAxis]])
    }
  })
  console.log(series)
  // ECharts 配置项
  option.value = {
    // title: {
    //   text: 'Mach Number vs Slip Angle'
    // },
    toolbox: {
      show: true,
      left: 'right',
      feature: {
        saveAsImage: { show: true },
        restore: { show: true },
        dataView: { show: true }
      }
    },
    tooltip: {
      trigger: 'axis'
    },
    legend: {
      data: Object.keys(groupedData).map(key => `${dictMap.get(form.groupKey)} ${key}`)
    },
    xAxis: {
      type: 'value',
      name: dictMap.get(form.xAxis)
    },
    yAxis: {
      type: 'value',
      name: dictMap.get(form.groupYAxis),
      min: minY,
      max: maxY
    },
    series
  }
}
const handleData = (xData, orderData, form, dictMap) => {
  console.log(xData, orderData)
  console.log(form)
  const data = []

  form.yAxis.forEach((item, index) => {
    /* data.push({
      xData
    }) */
    const a = []
    orderData.forEach(dataItem => {
      a.push(Number(dataItem[item]))
    })
    data.push({
      name: dictMap.get(item),
      xData: xData.map(Number),
      yData: a
    })
  })
  console.log(data)
  polynomialsData.value = data
}
const handleGroupData = (data, form, dictMap) => {
  const groupedData = data.reduce((result, currentValue) => {
    // 获取分组的key值
    (result[currentValue[form.groupKey]] = result[currentValue[form.groupKey]] || []).push(currentValue)
    return result
  }, {})
  console.log(groupedData)
  const _data = []
  Object.keys(groupedData).map(key => {
    const xData = []
    const yData = []
    groupedData[key].map(item => {
      xData.push(item[form.xAxis])
      yData.push(item[form.groupYAxis])
    })
    _data.push({
      name: `${dictMap.get(form.groupKey)} ${key}`,
      xData: xData.map(Number),
      yData: yData.map(Number)
    })
  })
  console.log(_data)
  polynomialsData.value = _data
}
const polynomialFit = (x, y, degree) => {
  const math = create(all)
  const X = []

  // 构建 X 矩阵
  for (let i = 0; i < x.length; i++) {
    const row = []
    for (let j = 0; j <= degree; j++) {
      row.push(Math.pow(x[i], j)) // 每一行是 x 的不同次方
    }
    X.push(row)
  }

  const XMatrix = math.matrix(X)
  const XT = math.transpose(XMatrix)
  const Y = math.matrix(y.map(val => [val])) // 确保 Y 是列矩阵

  // 计算 (XT * X)^-1 * XT * Y
  const B = math.multiply(
    math.inv(math.multiply(XT, XMatrix)),
    XT,
    Y
  )

  return B.toArray() // 返回多项式系数
}
/* const generatePolynomialExpression = (coefficients) => {
  let expression = ''
  for (let i = 0; i < coefficients.length; i++) {
    if (i === 0) {
      expression += `${coefficients[i]}`
    } else if (i === 1) {
      expression += ` + ${coefficients[i]} * x`
    } else {
      expression += ` + ${coefficients[i]} * x^${i}`
    }
  }
  return expression
} */
const generatePolynomialExpression = (coefficients) => {
  let expression = `${coefficients[0]}` // 第一个常数项直接添加

  for (let i = 1; i < coefficients.length; i++) {
    const coefficient = coefficients[i]
    const term = Math.abs(coefficient) + (i === 1 ? ' * x' : ` * x^${i}`)

    // 判断正负来决定是否添加符号
    expression += (coefficient >= 0 ? ' + ' : ' - ') + term
  }

  return expression
}

const fitPolynomials = () => {
  polynomialExpressions.value = [] // 清空之前的结果
  polynomialsData.value.forEach(item => {
    const { xData, yData, name } = item
    // console.log(xData)
    // console.log(yData)
    // 调用多项式拟合函数，假设拟合成二次多项式
    const degree = Number(times.value)
    const coefficients = polynomialFit(xData, yData, degree)
    const expression = generatePolynomialExpression(coefficients)
    polynomialExpressions.value.push({ name, expression })
    // 使用拟合结果生成拟合后的曲线数据
    /* const fittedYData = xData.map((x) => {
      return (
        coefficients[0] +
          coefficients[1] * x +
          coefficients[2] * x * x
      )
    })
    console.log(fittedYData) */
  })
}
const renderLatex = (expression) => {
  return katex.renderToString(expression, { throwOnError: false })
}
const copyToClipboard = (val) => {
  navigator.clipboard.writeText(val)
    .then(() => {
      proxy.$message.success('已复制到剪贴板')
      console.log('Text copied to clipboard')
    })
    .catch(err => {
      console.error('Failed to copy text: ', err)
    })
}
defineExpose({
  show
})
</script>

<template>
  <el-dialog
    v-model="dialogVisible"
    width="1200"
    :title="dlgTitle"
    draggable
    overflow
  >
    <div class="chart-container">
      <v-chart
        class="chart"
        :option="option"
        autoresize
      />
    </div>

    <el-button
      type="primary"
      @click="fitPolynomials"
    >
      拟合多项式
    </el-button>
    <div class="times-box">
      <span class="label-style">拟合次数:</span>
      <el-input
        v-model="times"
        style="width: 240px"
        placeholder="Please input"
      />
    </div>
    <div
      v-for="(item, index) in polynomialExpressions"
      :key="index"
      class="expression-box"
    >
      <span class="name-style">{{ item.name }}:</span>
      <span
        v-html="renderLatex(item.expression)"
      />
      <span style="margin-left: 16px">
        <el-link
          type="primary"
          @click="copyToClipboard(item.expression)"
        >
          复制
        </el-link>
      </span>
    </div>
  </el-dialog>
</template>

<style scoped lang="scss">
.chart-container {
  height: 500px;
}
.expression-box {
  margin-top: 16px;
  margin-bottom: 16px;
}
.name-style {
  display: inline-block;
  width: auto;
  margin-right: 16px;
}
.times-box {
  margin-top: 16px;
  .label-style {
    margin-right: 12px;
  }
}
</style>
